package com.starhub.domain.knowledge.service.impl;

import dev.langchain4j.store.embedding.EmbeddingSearchResult;
import dev.langchain4j.data.segment.TextSegment;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.starhub.application.rag.service.EmbeddingService;
import com.starhub.application.rag.service.MilvusFlushService;
import com.starhub.application.rag.service.RagService;
import com.starhub.application.rag.service.SegmentService;
import com.starhub.application.rag.util.EmbeddingSearchResultUtil;
import com.starhub.application.rag.vo.SegmentVo;
import com.starhub.common.bean.model.ModelConfig;
import com.starhub.domain.knowledge.dto.KnowledgeItemDto;
import com.starhub.domain.knowledge.entity.KnowledgeItem;
import com.starhub.domain.knowledge.mapper.KnowledgeItemMapper;
import com.starhub.domain.knowledge.result.KnowledgeItemsSearchResult;
import com.starhub.domain.knowledge.service.KnowledgeService;
import com.starhub.domain.knowledge.service.KnowledgeSettingService;
import com.starhub.domain.knowledge.vo.KnowledgeBaseVo;
import com.starhub.domain.knowledge.vo.KnowledgeCollectionVo;
import com.starhub.domain.knowledge.vo.KnowledgeItemVo;
import com.starhub.engine.generator.genid.IdGenerator;
import com.starhub.utils.Util;
import com.starhub.utils.HubBeanUtils;
import com.starhub.application.rag.dto.EmbeddingDto;
import com.starhub.application.rag.dto.RetrieveDto;
import com.starhub.application.rag.entity.Segment;
import com.starhub.application.rag.result.RagResult;

import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.starhub.application.collection.dto.DataManipulationDto;
import com.starhub.application.collection.entity.KnowledgeBase;
import com.starhub.application.collection.entity.KnowledgeCollection;
import com.starhub.application.collection.enums.MetaDataCollectionTypeEnums;
import com.starhub.application.collection.service.DataManipulationService;
import com.starhub.application.collection.service.KnowledgeBaseService;
import com.starhub.application.collection.service.KnowledgeCollectionService;
import com.starhub.application.interfaces.model.ModelConfigService;
import com.starhub.application.model.enums.VectorModelTypeEnum;
import com.starhub.application.model.util.DimensionUtil;

/**
 * 知识库相关Service实现类
 * @version: V1.0
 * @author: liuhf
 * @time 2025-06-05
 */
@Slf4j
@Service
public class KnowledgeServiceImpl extends ServiceImpl<KnowledgeItemMapper, KnowledgeItem> implements KnowledgeService {

    @Autowired
    private KnowledgeItemMapper knowledgeItemMapper;

    @Autowired
    private KnowledgeBaseService knowledgeBaseService;

    @Autowired
    private KnowledgeCollectionService knowledgeCollectionService;

    @Autowired
    private KnowledgeSettingService knowledgeSettingService;

    @Autowired
    private EmbeddingService embeddingService;

    @Autowired
    private RagService ragService;

    @Autowired
    private ModelConfigService modelConfigService;

    @Autowired
    private SegmentService segmentService;

    @Autowired
    private DataManipulationService dataManipulationService;
    
    @Autowired
    private MilvusFlushService milvusFlushService;
    
    /**
     * 创建知识条目
     * 
     * @param knowledgeItem 知识条目信息
     * @return 是否创建成功
     */
    @Override
    public String createKnowledgeItem(KnowledgeItemDto knowledgeItemDto, boolean isFlush) {
        
        KnowledgeItem knowledgeItem = HubBeanUtils.convert(knowledgeItemDto, KnowledgeItem.class);

        Long itemId = IdGenerator.generateId();

        // 生成ID和时间戳
        knowledgeItem.setId(itemId);
        knowledgeItem.setCreateTime(LocalDateTime.now());
        knowledgeItem.setUpdateTime(LocalDateTime.now());
        knowledgeItem.setIsEmbedded(0); // 初始状态为未向量化

        // 保存到数据库
        boolean success = knowledgeItemMapper.insert(knowledgeItem) > 0;
        if (!success) {
            throw new RuntimeException("保存知识条目失败");
        }

        KnowledgeCollection collection = knowledgeCollectionService.selectByIdAndNotDeleted(knowledgeItemDto.getCollectionId());
        if(collection == null) {
            throw new RuntimeException("知识库表不存在");
        }

        try {
            DataManipulationDto dataManipulationDto = convertDataManipulationDto(knowledgeItem);
            dataManipulationService.saveData(dataManipulationDto);
            
            // 更新向量化状态
            knowledgeItem.setIsEmbedded(1);
            knowledgeItem.setUpdateTime(LocalDateTime.now());
            knowledgeItemMapper.updateById(knowledgeItem);

            // 如果需要刷新，并且是向量表示，并且需要刷新
            if(isFlush 
                && collection.getMetaStorageType() == MetaDataCollectionTypeEnums.VECTOR_REPRESENTATION.getCode() 
                && milvusFlushService.needsFlush(collection.getCollectionIdentifier())){
                milvusFlushService.flushCollection(collection.getCollectionIdentifier());
            }
            
            return Util.null2String(itemId);
        } catch (Exception e) {
            // TODO 如果向量化失败，删除已保存的数据
            e.printStackTrace();
            log.error("知识条目向量化处理失败: {}", e.getMessage());
            throw new RuntimeException("知识条目向量化处理失败: " + e.getMessage(), e);
        }
    }

    /**
     * 更新知识条目
     * 
     * @param knowledgeItem 知识条目信息
     * @return 是否更新成功
     */
    @Override
    public boolean updateKnowledgeItem(KnowledgeItemDto knowledgeItemDto) {
        if (knowledgeItemDto.getId() == null) {
            throw new IllegalArgumentException("知识条目ID不能为空");
        }

        // 获取原数据
        KnowledgeItem existingItem = knowledgeItemMapper.selectById(knowledgeItemDto.getId());
        if (existingItem == null) {
            throw new IllegalArgumentException("知识条目不存在");
        }

        KnowledgeItem knowledgeItem = HubBeanUtils.convert(knowledgeItemDto, KnowledgeItem.class);

        // 更新基本信息
        knowledgeItem.setUpdateTime(LocalDateTime.now());
        knowledgeItem.setIsEmbedded(0); // 重置为未向量化状态

        boolean success = knowledgeItemMapper.updateById(knowledgeItem) > 0;
        if (!success) {
            throw new RuntimeException("更新知识条目失败");
        }

        try {
            DataManipulationDto dataManipulationDto = convertDataManipulationDto(knowledgeItem);
            dataManipulationService.updateData(dataManipulationDto);

            // 更新向量化状态
            knowledgeItem.setIsEmbedded(1);
            knowledgeItem.setUpdateTime(LocalDateTime.now());
            knowledgeItemMapper.updateById(knowledgeItem);

            return true;
        } catch (Exception e) {
            throw new RuntimeException("知识条目向量化处理失败: " + e.getMessage(), e);
        }
    }

    /**
     * 删除知识条目（软删除）
     * 
     * @param id 知识条目ID
     * @return 是否删除成功
     */
    @Override
    public boolean deleteKnowledgeItem(Long id) {
        KnowledgeItem _knowledgeItem = knowledgeItemMapper.selectById(id);
        if (_knowledgeItem == null) {
            throw new IllegalArgumentException("知识条目不存在");
        }

        /*DataManipulationDto dataManipulationDto = convertDataManipulationDto(_knowledgeItem);
        dataManipulationService.deleteData(dataManipulationDto);*/
        
        // 删除向量数据
        EmbeddingDto embeddingDto = convertEmbeddingDto(_knowledgeItem);
        deleteEmbedding(embeddingDto);
        // 删除段落数据
        segmentService.deleteByItemId(id);

        // 删除知识条目
        KnowledgeItem knowledgeItem = new KnowledgeItem();
        knowledgeItem.setId(id);
        knowledgeItem.setDeleteType(1);

        return knowledgeItemMapper.updateById(knowledgeItem) > 0;
    }

    /**
     * 转换DataManipulationDto
     * @param knowledgeItem
     * @return
     */
    private DataManipulationDto convertDataManipulationDto(KnowledgeItem knowledgeItem) {
        return DataManipulationDto.builder()
                .itemId(Util.null2String(knowledgeItem.getId()))
                .collectionId(Util.null2String(knowledgeItem.getCollectionId()))
                .baseId(Util.null2String(knowledgeItem.getBaseId()))
                .content(knowledgeItem.getContent())
                .answerContent(knowledgeItem.getAnswerContent())
                .build();
    }

    /**
     * 根据ID获取知识库
     * 
     * @param id 知识库ID
     * @return 知识库信息
     */
    @Override
    public KnowledgeBaseVo getKnowledgeBaseById(Long id) {
        //TODO 权限校验
        return knowledgeSettingService.getKnowledgeBaseById(id);
    }

    /**
     * 根据ID获取知识库表
     * 
     * @param id 知识库表ID
     * @return 知识库表信息
     */
    @Override
    public KnowledgeCollectionVo getKnowledgeCollectionById(Long id) {
        //TODO 权限校验
        return knowledgeSettingService.getKnowledgeCollectionById(id);
    }

    /**
     * 根据ID获取知识条目
     * 
     * @param id 知识条目ID
     * @return 知识条目信息
     */
    @Override
    public KnowledgeItemVo getKnowledgeItemById(Long id) {
        LambdaQueryWrapper<KnowledgeItem> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(KnowledgeItem::getId, id)
                   .eq(KnowledgeItem::getDeleteType, 0);        
        KnowledgeItem knowledgeItem = knowledgeItemMapper.selectOne(queryWrapper);

        KnowledgeItemVo knowledgeItemVo = HubBeanUtils.convert(knowledgeItem, KnowledgeItemVo.class);
        return knowledgeItemVo;
    }

    /**
     * 根据内容获取知识条目
     * @param collectionId 知识库表ID
     * @param content 知识条目内容
     * @return 知识条目信息
     */
    @Override
    public KnowledgeItemVo getKnowledgeItemByContent(String collectionId, String content) {
        LambdaQueryWrapper<KnowledgeItem> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(KnowledgeItem::getContent, content)
                   .eq(KnowledgeItem::getCollectionId, collectionId)
                   .eq(KnowledgeItem::getDeleteType, 0);        
        KnowledgeItem knowledgeItem = knowledgeItemMapper.selectOne(queryWrapper);

        KnowledgeItemVo knowledgeItemVo = HubBeanUtils.convert(knowledgeItem, KnowledgeItemVo.class);
        return knowledgeItemVo;
    }

    /**
     * 分页查询知识条目
     * 
     * @param collectionId 知识库表ID
     * @param current      当前页码
     * @param size         每页大小
     * @param keyword      搜索关键词（可选）
     * @return 分页结果
     */
    @Override
    public KnowledgeItemsSearchResult pageKnowledgeItems(Long collectionId, Long current, Long size, String keyword) {
        // 创建分页对象
        Page<KnowledgeItem> page = new Page<>(current, size);

        // 构建查询条件
        LambdaQueryWrapper<KnowledgeItem> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(KnowledgeItem::getCollectionId, collectionId)
                .eq(KnowledgeItem::getDeleteType, 0); // 未删除的记录

        // 如果有关键词，添加内容模糊搜索条件
        if (!Util.isEmpty(keyword)) {
            queryWrapper.like(KnowledgeItem::getContent, keyword);
        }

        // 按创建时间倒序排序
        queryWrapper.orderByDesc(KnowledgeItem::getCreateTime);

        // 执行分页查询
        Page<KnowledgeItem> resultPage = knowledgeItemMapper.selectPage(page, queryWrapper);

        // 转换
        List<KnowledgeItemVo> result = page.getRecords().stream()
                .map(item -> HubBeanUtils.convert(item, KnowledgeItemVo.class))
                .toList();

        return KnowledgeItemsSearchResult.success(result, resultPage.getTotal(), resultPage.getSize(),
                resultPage.getCurrent());
    }

    /**
     * 在指定知识库表中检索文本
     * 
     * @param collectionId 知识库表ID
     * @param queryText    检索文本
     * @param topK         返回最相似的前K条记录
     * @return 检索结果列表
     */
    @Override
    public List<SegmentVo> searchSegments(Long collectionId, String queryText, Integer topK,
            Double minScore) {
        // 1. 参数校验
        if (collectionId == null || queryText == null || queryText.trim().isEmpty()) {
            throw new IllegalArgumentException("参数不能为空");
        }
        if (topK == null || topK <= 0) {
            topK = 5; // 默认返回5条记录
        }

        // 2. 获取知识库表信息
        KnowledgeCollectionVo collection = getKnowledgeCollectionById(collectionId);
        if (collection == null) {
            throw new IllegalArgumentException("知识库表不存在");
        }

        // 3. 校验知识库是否存在
        KnowledgeBaseVo knowledgeBase = getKnowledgeBaseById(collection.getBaseId());
        if (knowledgeBase == null) {
            throw new IllegalArgumentException("所属知识库不存在");
        }

        // 3. 调用向量服务进行相似度搜索
        try {
            RagResult ragResult = ragService.retrieve(
                    RetrieveDto.builder()
                            .queryText(queryText)
                            .topK(topK)
                            .minScore(minScore)
                            .vectorModel(knowledgeBase.getVectorModel())
                            .dimension(DimensionUtil.getDimension(knowledgeBase.getVectorModel()))
                            .collectionId(Util.null2String(collection.getId()))
                            .collectionIdentifier(collection.getCollectionIdentifier())
                            .build());

            // 对象转换
            EmbeddingSearchResult<TextSegment> searchResult = ragResult.getSearchResult();

            List<String> segmentIds = EmbeddingSearchResultUtil.transToSegmentIds(searchResult);
            if (segmentIds == null || segmentIds.isEmpty()) {
                return null;
            }

            // 查询所有segment
            List<Segment> segments = segmentService.listByIds(segmentIds);
            if (segments == null || segments.isEmpty()) {
                return null;
            }

            // 按照segmentIds的顺序重新排序segments 和转换SegmentVo
            return segmentIds.stream()
                    .map(id -> segments.stream()
                            .filter(segment -> segment.getId().toString().equals(id))
                            .findFirst()
                            .orElse(null))
                    .filter(segment -> segment != null)
                    .map(segment -> HubBeanUtils.convert(segment, SegmentVo.class))
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("文本检索失败", e);
            throw new RuntimeException("文本检索失败: " + e.getMessage());
        }
    }

    /**
     * 转换EmbddingDto
     * @param knowledgeItem
     * @return
     */
    private EmbeddingDto convertEmbeddingDto(KnowledgeItem knowledgeItem) {
        // 获取知识库表信息
        KnowledgeCollection collection = knowledgeCollectionService.selectByIdAndNotDeleted(knowledgeItem.getCollectionId());
        if (collection == null) {
            throw new IllegalArgumentException("知识库表不存在");
        }

        // 获取知识库信息
        KnowledgeBase knowledgeBase = knowledgeBaseService.selectByIdAndNotDeleted(collection.getBaseId());
        if (knowledgeBase == null) {
            throw new IllegalArgumentException("知识库不存在");
        }

        // 获取模型配置
        ModelConfig config = modelConfigService.getModel(knowledgeBase.getVectorModel());

        EmbeddingDto embeddingDto = EmbeddingDto.builder()
                .itemId(Util.null2String(knowledgeItem.getId()))
                .collectionId(Util.null2String(collection.getId()))
                .baseId(Util.null2String(knowledgeBase.getId()))
                .content(knowledgeItem.getContent())
                .collectionIdentifier(collection.getCollectionIdentifier())
                .chartType(config.getChatType())
                .vectorModel(knowledgeBase.getVectorModel())
                .dimension(DimensionUtil._getDimension(config))
                .baseType(knowledgeBase.getBaseType())
                .splitStrategy(knowledgeBase.getSplitStrategy())
                .maxParagraphSize(knowledgeBase.getMaxParagraphSize())
                .maxOverlapSize(knowledgeBase.getMaxOverlapSize())
                .build();
                
        return embeddingDto;
    }

    /**
     * 删除向量数据
     * 
     * @param knowledgeItemDto
     */
    private void deleteEmbedding(EmbeddingDto embeddingDto) {
        try {
            embeddingService.deleteEmbedding(embeddingDto);
        } catch (Exception e) {
            throw new RuntimeException("删除向量数据失败: " + e.getMessage(), e);
        }
    }
}